package com.bestcem.xm.member.grpc.service;

import cn.hutool.core.collection.CollUtil;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.member.enums.SyncTypeEnum;
import com.bestcem.xm.member.grpc.service.param.syncrule.*;
import com.bestcem.xm.member.grpc.v1.common.CreateResponse;
import com.bestcem.xm.member.grpc.v1.services.*;
import com.bestcem.xm.member.service.SyncRuleService;
import com.bestcem.xm.member.service.dto.SyncRuleDTO;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author ming.xue <ming.xue@idiaoyan.com>
 * @desc 同步规则服务
 * @date 2021-08-02
 */
@GrpcService
public class SyncRuleGrpcService extends SyncRuleServiceGrpc.SyncRuleServiceImplBase {
    /**
     * 同步规则服务
     */
    @Autowired
    private SyncRuleService syncRuleService;

    /**
     * 获取同步规则
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void getSyncRule(GetSyncRuleRequest request,
                            StreamObserver<GetSyncRuleResponse> responseObserver) {
        GetSyncRuleResponse.Builder builder = GetSyncRuleResponse.newBuilder();

        // 参数转换
        GetSyncRuleParam param = new GetSyncRuleParam();
        param.setOrgId(request.getOrgId());
        param.setMemberType(request.getMemberTypeValue());

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 获取同步规则
        ServiceResult<SyncRuleDTO> result = syncRuleService.getSyncRule(param);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 处理结果返回
        SyncRuleDTO syncRuleDTO = result.getData();
        SyncRule syncRule = this.toSyncRule(syncRuleDTO);
        responseObserver.onNext(builder.setStatus(RpcStatusResult.success()).setSyncRule(syncRule).build());
        responseObserver.onCompleted();
    }

    /**
     * 创建同步规则
     */
    @Override
    public void createSyncRule(CreateSyncRuleRequest request,
                               StreamObserver<CreateResponse> responseObserver) {
        CreateResponse.Builder builder = CreateResponse.newBuilder();

        // 参数转换
        CreateSyncRuleParam param = new CreateSyncRuleParam();
        if (request.hasSyncRule()) {
            SyncRule rule = request.getSyncRule();
            param.setOrgId(rule.getOrgId());
            param.setMemberType(rule.getMemberTypeValue());
            param.setSyncType(rule.getRespondentEnabled() ? SyncTypeEnum.NOW.getIndex() : SyncTypeEnum.NEVER.getIndex());
            param.setQueryFields(rule.getQueryFieldsList());
            param.setUpdateFields(rule.getUpdateFieldsList());
        }

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 创建同步规则
        ServiceResult<String> result = syncRuleService.createSyncRule(param);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 处理结果返回
        String syncRuleId = StringUtils.trimToEmpty(result.getData());
        responseObserver.onNext(builder.setStatus(RpcStatusResult.success()).setId(syncRuleId).build());
        responseObserver.onCompleted();
    }

    /**
     * 修改同步规则
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void updateSyncRule(UpdateSyncRuleRequest request,
                               StreamObserver<UpdateSyncRuleResponse> responseObserver) {
        UpdateSyncRuleResponse.Builder builder = UpdateSyncRuleResponse.newBuilder();

        // 参数转换
        UpdateSyncRuleParam param = new UpdateSyncRuleParam();
        if (request.hasSyncRule()) {
            SyncRule syncRule = request.getSyncRule();
            param.setId(param.getId());
            param.setSyncType(syncRule.getRespondentEnabled() ? SyncTypeEnum.NOW.getIndex() : SyncTypeEnum.NEVER.getIndex());
            param.setQueryFields(syncRule.getQueryFieldsList());
            param.setUpdateFields(syncRule.getUpdateFieldsList());
        }

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 修改同步规则
        ServiceResult<SyncRuleDTO> result = syncRuleService.updateSyncRule(param);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 处理结果返回
        SyncRuleDTO syncRuleDTO = result.getData();
        responseObserver.onNext(builder.setStatus(RpcStatusResult.success())
                .setSyncRule(this.toSyncRule(syncRuleDTO)).build());
        responseObserver.onCompleted();
    }

    /**
     * 获取默认同步规则字段列表
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void listDefaultSyncRuleFields(ListDefaultSyncRuleFieldsRequest request,
                                          StreamObserver<ListDefaultSyncRuleFieldsResponse> responseObserver) {
    }

    /**
     * 重置同步规则
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void restoreSyncRule(RestoreSyncRuleRequest request,
                                StreamObserver<RestoreSyncRuleResponse> responseObserver) {
    }

    /**
     * 批量更新同步规则
     *
     * @param request
     * @param responseObserver
     */
    @Override
    public void batchUpdateSyncRule(BatchUpdateSyncRuleRequest request,
                                    StreamObserver<BatchUpdateSyncRuleResponse> responseObserver) {
        BatchUpdateSyncRuleResponse.Builder builder = BatchUpdateSyncRuleResponse.newBuilder();

        // 参数转换
        BatchUpdateSyncRuleParam param = requestToBatchUpdateSyncRuleParam(request);

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(param);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        // 修改同步规则
        ServiceResult<Void> result = syncRuleService.batchUpdateSyncRule(param);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        responseObserver.onNext(builder.setStatus(RpcStatusResult.success()).build());
        responseObserver.onCompleted();
    }

    /**
     * request To BatchUpdateSyncRuleParam
     *
     * @param request
     * @return
     */
    private BatchUpdateSyncRuleParam requestToBatchUpdateSyncRuleParam(BatchUpdateSyncRuleRequest request) {
        BatchUpdateSyncRuleParam param = new BatchUpdateSyncRuleParam();
        List<SyncRule> rulesList = request.getRulesList();
        if (CollUtil.isNotEmpty(rulesList)) {
            List<BatchUpdateSyncRule> rules = rulesList.stream().map(rule -> {
                BatchUpdateSyncRule syncRule = new BatchUpdateSyncRule();
                // 组织id
                syncRule.setOrgId(rule.getOrgId());
                // 联系人类型
                syncRule.setMemberType(rule.getMemberTypeValue());
                // 同步规则
                syncRule.setSyncType(rule.getRespondentEnabled() ? SyncTypeEnum.NOW.getIndex() : SyncTypeEnum.NEVER.getIndex());
                syncRule.setWechatSyncType(rule.getWechatEnabled() ? SyncTypeEnum.NOW.getIndex() : SyncTypeEnum.NEVER.getIndex());
                return syncRule;
            }).collect(Collectors.toList());
            param.setRules(rules);
        }
        return param;
    }

    /**
     * 类型转换
     *
     * @param syncRuleDTO
     * @return
     */
    private SyncRule toSyncRule(SyncRuleDTO syncRuleDTO) {
        SyncRule.Builder builder = SyncRule.newBuilder();
        if (syncRuleDTO == null) {
            return builder.build();
        }
        GRpcUtil.fillDefaultValue(syncRuleDTO);

        return builder.setId(syncRuleDTO.getId())
                .setMemberTypeValue(syncRuleDTO.getMemberType())
                .setRespondentEnabled(syncRuleDTO.getType() == SyncTypeEnum.NOW.getIndex())
                .addAllQueryFields(syncRuleDTO.getQueryFields())
                .addAllUpdateFields(syncRuleDTO.getUpdateFields())
                .build();
    }
}
